home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
ai
/
vgamaze4
/
sqrmaze.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-16
|
25KB
|
622 lines
#include <iostream.h>
#include "oracle.h"
#include "cell.h"
#include "titillat.h"
#include "sqrmaze.h"
#define TRUE -1
#define FALSE 0
typedef cell *cell_ptr;
maze::maze(int row_count,int column_count,int thickness_of_wall,char *seed)
// Contruct a maze having "row_count" rows and "column_count" columns of
// rooms. The walls should be "thickness_of_wall" (bricks) thick. A different
// (8 character of less) "seed" generally yields a different maze.
{
struct
{
int row_num;
int column_num;
} delta [4];
int mud_filled_room_found;
struct
{
int row_num;
int column_num;
} next;
char wall [24] [4];
char wall_to_check;
char wall_num;
char way_out;
// Allocate a two dimensional array of rooms.
num_rows=row_count;
num_columns=column_count;
if (memory_allocated=((room=new cell_ptr[num_rows]) != NULL))
{
int row_num=0;
while ((memory_allocated) && (row_num < num_rows))
if (memory_allocated=((room[row_num]=new cell [num_columns]) != NULL))
row_num++;
if (! memory_allocated)
{
while (row_num)
delete [] room[--row_num];
delete [] room;
cerr << "Fatal error: cannot allocate maze." << '\n';
}
}
if (memory_allocated)
{
wall_thickness=thickness_of_wall;
// Set up the directions by which a room can be exited.
delta[0].row_num=-1; // north
delta[0].column_num=0;
delta[1].row_num=0; // west
delta[1].column_num=-1;
delta[2].row_num=1; // south
delta[2].column_num=0;
delta[3].row_num=0; // east
delta[3].column_num=1;
int order_num=0;
// Set up the 4! orders in which the wall of a room can be accessed.
for (int wall_num_1=0; wall_num_1 < 4; wall_num_1++)
for (int wall_num_2=0; wall_num_2 < 4; wall_num_2++)
if (wall_num_2 != wall_num_1)
for (int wall_num_3=0; wall_num_3 < 4; wall_num_3++)
if ((wall_num_3 != wall_num_2)
&& (wall_num_3 != wall_num_1))
for (int wall_num_4=0; wall_num_4 < 4; wall_num_4++)
if ((wall_num_4 != wall_num_3)
&& (wall_num_4 != wall_num_2)
&& (wall_num_4 != wall_num_1))
{
wall[order_num][wall_num_4]='\0';
wall[order_num][wall_num_3]='\1';
wall[order_num][wall_num_2]='\2';
wall[order_num][wall_num_1]='\3';
order_num++;
}
titillator_ptr=new titillator;
order_selector=new oracle(&seed[0],order_num);
row_selector=new oracle(&seed[0],num_rows);
column_selector=new oracle(&seed[0],num_columns);
int finished=FALSE;
// Generate mazes until you have one that is hard to solve.
do
{
// Pick a starting room.
first.row_num=row_selector->random_number();
first.column_num=column_selector->random_number();
current.row_num=first.row_num;
current.column_num=first.column_num;
// Excavate the starting room.
room[current.row_num][current.column_num].mark_floor(' ');
// Pick the order in which the walls of the starting room will be
// considered.
room[current.row_num][current.column_num].set_order(
order_selector->random_number());
titillator_ptr->titillate();
// Excavate rooms until there are no more to excavate.
do
{
mud_filled_room_found=FALSE;
// Find an adjacent room (not yet considered) that needs
// excavating.
do
{
wall_num=room[current.row_num][
current.column_num].next_wall_num();
if (wall_num < '\4')
{
wall_to_check=wall[room[current.row_num][
current.column_num].order_to_check()][wall_num];
if (room[current.row_num][
current.column_num].wall_up(wall_to_check))
{
next.row_num=current.row_num
+delta[wall_to_check].row_num;
if ((next.row_num >= 0)
&& (next.row_num < num_rows))
{
next.column_num=current.column_num
+delta[wall_to_check].column_num;
if ((next.column_num >= 0)
&& (next.column_num < num_columns))
{
if (room[next.row_num][
next.column_num].mark()
== 'M')
mud_filled_room_found=TRUE;
}
}
}
}
}
while ((wall_num < '\4')
&& (! mud_filled_room_found));
if (mud_filled_room_found)
// an adjacent room needs excavating
{
// Exit the current room, knocking down a wall.
room[current.row_num][
current.column_num].knock_down_wall(wall_to_check);
way_out=char(((int) wall_to_check+2)%4);
// Enter the adjacent room, knocking down a wall.
room[next.row_num][next.column_num].knock_down_wall(
way_out);
// Record how to return to the previous room.
room[next.row_num][next.column_num].set_way_out(
way_out);
current.row_num=next.row_num;
current.column_num=next.column_num;
// Excavate the room.
room[current.row_num][current.column_num].mark_floor(' ');
// Select the order in which the walls of the room will
// be considered.
room[current.row_num][current.column_num].set_order(
order_selector->random_number());
}
else
// no adjacent room needs excavating
{
if ((first.row_num != current.row_num)
|| (first.column_num != current.column_num))
// not in starting room
{
// Go back to the room from which you entered
// the current room.
next.row_num=current.row_num+delta[
room[current.row_num][
current.column_num].way_back()].row_num;
next.column_num=current.column_num+delta[
room[current.row_num][
current.column_num].way_back()].column_num;
current.row_num=next.row_num;
current.column_num=next.column_num;
}
}
}
while ((first.row_num != current.row_num)
|| (first.column_num != current.column_num)
|| (wall_num < '\4'));
if (maze_okay()) // Maze is hard to solve.
finished=TRUE;
else // Prepare to try another maze.
for (int row_num=0; row_num < num_rows; row_num++)
for (int column_num=0; column_num < num_columns; column_num++)
room[row_num][column_num].reinitialize();
}
while (! finished);
// Knock down walls blocking the entrance and exit to the maze.
room[0][0].knock_down_wall(0);
room[num_rows-1][num_columns-1].knock_down_wall(2);
delete column_selector;
delete row_selector;
delete order_selector;
delete titillator_ptr;
}
}
maze::~maze()
{
if (memory_allocated)
{
// Free the two dimensional array of rooms.
for (int row_num=0; row_num < num_rows; row_num++)
delete [] room[row_num];
delete [] room;
}
}
int maze::maze_okay()
{
int adjacency;
struct
{
int row_num;
int column_num;
} delta [4];
struct
{
int row_num;
int column_num;
} next;
int num_rooms_in_solution;
int passage_found;
struct
{
int row_num;
int column_num;
} previous;
int result;
struct
{
int row_num;
int column_num;
} saved;
char wall_to_check;
char way_out;
// Set up the directions by which a room can be exited.
delta[0].row_num=-1; // north
delta[0].column_num=0;
delta[1].row_num=0; // west
delta[1].column_num=-1;
delta[2].row_num=1; // south
delta[2].column_num=0;
delta[3].row_num=0; // east
delta[3].column_num=1;
// Solve the maze.
// Start at the entrance.
current.row_num=0;
current.column_num=0;
// Mark the room as part of the solution.
room[current.row_num][current.column_num].mark_floor('S');
num_rooms_in_solution=1;
// Prepare to consider all the walls of the room.
room[current.row_num][current.column_num].zero_wall_to_check();
// Try rooms until you get to the exit.
do
{
// Find a passage (not yet considered) out of the current room leading
// to a room not part of the proposed solution.
passage_found=FALSE;
do
{
wall_to_check
=room[current.row_num][current.column_num].next_wall_num();
if (wall_to_check < '\4')
{
if (! (room[current.row_num][
current.column_num].wall_up(wall_to_check)))
{
next.row_num=current.row_num
+delta[wall_to_check].row_num;
if ((next.row_num >= 0)
&& (next.row_num < num_rows))
{
next.column_num=current.column_num
+delta[wall_to_check].column_num;
if ((next.column_num >= 0)
&& (next.column_num < num_columns))
{
if (room[next.row_num][
next.column_num].mark()
== ' ')
passage_found=TRUE;
}
}
}
}
}
while ((! passage_found) && (wall_to_check < '\4'));
if (passage_found)
// passage to room not currently part of proposed solution found
{
// Enter the room.
current.row_num=next.row_num;
current.column_num=next.column_num;
// Record the way back to the previous room.
way_out=char(((int) wall_to_check+2)%4);
room[current.row_num][current.column_num].set_way_out(way_out);
// Mark the room as part of the proposed solution.
room[current.row_num][current.column_num].mark_floor('S');
num_rooms_in_solution++;
// Prepare to consider all the walls of the room.
room[current.row_num][current.column_num].zero_wall_to_check();
}
else
// dead end
{
// Mark current room as not part of proposed solution.
room[current.row_num][current.column_num].mark_floor(' ');
num_rooms_in_solution--;
// Go back to the room from which this room was entered.
next.row_num=current.row_num+delta[
room[current.row_num][current.column_num].way_back()].row_num;
next.column_num=current.column_num+delta[
room[current.row_num][current.column_num].way_back()].column_num;
current.row_num=next.row_num;
current.column_num=next.column_num;
}
}
while((current.row_num != num_rows-1)
|| (current.column_num != num_columns-1));
// Now that the maze is solved, calculate the number of rooms in the
// solution (or outside the maze) that are adjacent to the rooms in
// the solution.
adjacency=0;
previous.row_num=-1;
previous.column_num=0;
current.row_num=0;
current.column_num=0;
do
{
for (wall_to_check='\0'; wall_to_check < '\4'; wall_to_check++)
if (room[current.row_num][current.column_num].wall_up(wall_to_check))
{
next.row_num=current.row_num+delta[wall_to_check].row_num;
if ((next.row_num >= 0)
&& (next.row_num < num_rows))
{
next.column_num=current.column_num
+delta[wall_to_check].column_num;
if ((next.column_num >= 0)
&& (next.column_num < num_columns))
{
if (room[next.row_num][next.column_num].mark() == 'S')
adjacency++;
}
else
adjacency++;
}
else
adjacency++;
}
else
{
next.row_num=current.row_num+delta[wall_to_check].row_num;
if ((next.row_num >= 0)
&& (next.row_num < num_rows))
{
next.column_num=current.column_num
+delta[wall_to_check].column_num;
if ((next.column_num >= 0)
&& (next.column_num < num_columns))
{
if ((room[next.row_num][next.column_num].mark() == 'S')
&& ((previous.row_num != next.row_num)
|| (previous.column_num != next.column_num)))
{
saved.row_num=next.row_num;
saved.column_num=next.column_num;
}
}
}
}
previous.row_num=current.row_num;
previous.column_num=current.column_num;
current.row_num=saved.row_num;
current.column_num=saved.column_num;
}
while((current.row_num != num_rows-1)
|| (current.column_num != num_columns-1));
for (wall_to_check='\0'; wall_to_check < '\4'; wall_to_check++)
if (room[current.row_num][current.column_num].wall_up(wall_to_check))
{
next.row_num=current.row_num+delta[wall_to_check].row_num;
if ((next.row_num >= 0)
&& (next.row_num < num_rows))
{
next.column_num=current.column_num
+delta[wall_to_check].column_num;
if ((next.column_num >= 0)
&& (next.column_num < num_columns))
{
if (room[next.row_num][next.column_num].mark() == 'S')
adjacency++;
}
else
adjacency++;
}
else
adjacency++;
}
// The maze is hard to solve (from the outside) if more than a third of its
// rooms are part of its solution and rooms not part of its solution tend to
// be next to rooms in its solution.
if ((3*num_rooms_in_solution >= num_rows*num_columns)
&& (9*adjacency <= 8*num_rooms_in_solution))
result=TRUE;
else
result=FALSE;
return result;
}
int maze::external_to_maze(double x,double y)
// Return TRUE if and only if a point (x,y) is external to the maze.
{
int result;
if (y < 0.0)
result=TRUE;
else
if (y > double(3*wall_thickness*num_columns+wall_thickness-1))
result=TRUE;
else
if (x < 0.0)
result=TRUE;
else
if (x > double(3*wall_thickness*num_rows+wall_thickness-1))
result=TRUE;
else
result=FALSE;
return result;
}
double maze::f(double x,double y)
// Return 6.0*wall_thickness if a point (x,y) is on a wall, 0.0 otherwise.
{
double z;
if (y < 0.0)
z=0.0;
else
if (y > double(3*wall_thickness*num_columns+wall_thickness-1))
z=0.0;
else
if (x < 0.0)
z=0.0;
else
if (x > double(3*wall_thickness*num_rows+wall_thickness-1))
z=0.0;
else
{
int tem_int=int(y);
int column_num=tem_int/(3*wall_thickness);
int y_mod_3_wall_thickness=tem_int-3*wall_thickness*column_num;
tem_int=int(x);
int row_num=tem_int/(3*wall_thickness);
int x_mod_3_wall_thickness=tem_int-3*wall_thickness*row_num;
if (row_num < num_rows)
if (column_num < num_columns)
if (x_mod_3_wall_thickness < wall_thickness)
if (y_mod_3_wall_thickness < wall_thickness)
// northwest corner
z=1.0;
else
// north wall
if (room[row_num][column_num].wall_up('\0'))
z=1.0;
else
z=0.0;
else
if (y_mod_3_wall_thickness < wall_thickness)
// west wall
if (room[row_num][column_num].wall_up('\1'))
z=1.0;
else
z=0.0;
else
// in room
z=0.0;
else
// east most wall
z=1.0;
else
// south most wall
if (column_num < num_columns)
if (y_mod_3_wall_thickness < wall_thickness)
// southwest corner
z=1.0;
else
// south wall
if (room[num_rows-1][column_num].wall_up('\2'))
z=1.0;
else
z=0.0;
else
// southeast most corner
z=1.0;
}
return z*double(6*wall_thickness);
}
int maze::part_of_solution(double x,double y)
// Return TRUE if and only if a point (x,y) is on a wall outlining the
// solution to the maze.
{
int result;
if (y < 0.0)
result=FALSE;
else
if (y > double(3*wall_thickness*num_columns+wall_thickness-1))
result=FALSE;
else
if (x < 0.0)
result=FALSE;
else
if (x > double(3*wall_thickness*num_rows+wall_thickness-1))
result=FALSE;
else
{
int tem_int=int(y);
int column_num=tem_int/(3*wall_thickness);
int y_mod_3_wall_thickness=tem_int-3*wall_thickness*column_num;
tem_int=int(x);
int row_num=tem_int/(3*wall_thickness);
int x_mod_3_wall_thickness=tem_int-3*wall_thickness*row_num;
if (row_num < num_rows)
if (column_num < num_columns)
if (x_mod_3_wall_thickness < wall_thickness)
if (y_mod_3_wall_thickness < wall_thickness)
// northwest corner
if ((room[row_num][column_num].mark() == 'S')
|| ((row_num > 0)
&& (room[row_num-1][column_num].mark() == 'S'))
|| ((column_num > 0)
&& (room[row_num][column_num-1].mark() == 'S'))
|| ((row_num > 0) && (column_num > 0)
&& (room[row_num-1][column_num-1].mark() == 'S')))
result=TRUE;
else
result=FALSE;
else
// north wall
if (room[row_num][column_num].wall_up('\0'))
if ((room[row_num][column_num].mark() == 'S')
|| ((row_num > 0)
&& (room[row_num-1][column_num].mark() == 'S')))
result=TRUE;
else
result=FALSE;
else
result=FALSE;
else
if (y_mod_3_wall_thickness < wall_thickness)
// west wall
if (room[row_num][column_num].wall_up('\1'))
if ((room[row_num][column_num].mark() == 'S')
|| ((column_num > 0)
&& (room[row_num][column_num-1].mark() == 'S')))
result=TRUE;
else
result=FALSE;
else
result=FALSE;
else
// in room
result=FALSE;
else
// east most wall
if (x_mod_3_wall_thickness < wall_thickness)
// northeast corner
if ((room[row_num][num_columns-1].mark() == 'S')
|| ((row_num > 0)
&& (room[row_num-1][num_columns-1].mark() == 'S')))
result=TRUE;
else
result=FALSE;
else
// east wall
if (room[row_num][num_columns-1].mark() == 'S')
result=TRUE;
else
result=FALSE;
else
// south most wall
if (column_num < num_columns)
if (y_mod_3_wall_thickness < wall_thickness)
// southwest corner
if ((room[num_rows-1][column_num].mark() == 'S')
|| ((column_num > 0)
&& (room[num_rows-1][column_num-1].mark() == 'S')))
result=TRUE;
else
result=FALSE;
else
// south wall
if (room[num_rows-1][column_num].wall_up('\2'))
if (room[num_rows-1][column_num].mark() == 'S')
result=TRUE;
else
result=FALSE;
else
result=FALSE;
else
// southeast most corner
if (room[num_rows-1][num_columns-1].mark() == 'S')
result=TRUE;
else
result=FALSE;
}
return result;
}